/* Soubor je ulozen v kodovani UTF-8.
 * Kontrola kódování: Příliš žluťoučký kůň úpěl ďábelské ódy. */

package cz.vse.adventura.po1715.cerj117_cermak.hra;

import cz.pecinovsky.english.pojj.adv_framework.game_txt.INamed;
import cz.pecinovsky.english.pojj.adv_framework.game_txt.ICommand;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;





/*******************************************************************************
 * Instance třídy {@code Příkaz} přesněji instance jejích potomků) mají
 * na starost interpretaci přikazů zadávaných uživatelem hrajícím danou hru.
 * Třída {@code APříkaz} je rodičovskou třídou všech přikazů.
 *
 * @author    Jiří Čermák
 * @version   1.00.000
 */
abstract class Příkaz implements ICommand
{
//== KONSTANTNÍ ATRIBUTY TŘÍDY =================================================
    
    private static final String UVÍTÁNÍ = 
            "Vítám Tě ve hře STIHNI VLAK A NEPOSER SE. " +
            "\nJsi právě na cestě na vlak do Prahy, ale zaskočila Tě základní lidská potřeba." +
            "\nNení to sex ani jídlo, ale toaleta. Co teď?" +
            "\n\nNacházíte se v místnosti: Náměstí" +
          "\nMůžete se přesunout do místností: park, pěší zóna, banka, hospoda" +
          "\nV místnosti se nachází: kašna, strom, auto, babička" +
          "\nMáte v držení předměty: ";

    private static final String PRÁZDNÝ = 
            "Zadal(a) jste prázdný příkaz. Chcete-li poradit, zadejte příkaz ?";

    private static final String NEZNÁM = 
            "Tento příkaz neznám. Chcete-li poradit, zadejte příkaz ?";

    private static final Map<String, ICommand> název2příkaz =
                                             new HashMap<String, ICommand>();

     private static final Příkaz
            PŘÍKAZ_HELP  = new PříkazHelp(),
            PŘÍKAZ_JDI   = new PříkazJdi(),
            PŘÍKAZ_VEZMI = new PříkazVezmi(),
            PŘÍKAZ_POLOZ = new PříkazPolož(),
            PŘÍKAZ_UMYJ = new PříkazUmyj(),
            PŘÍKAZ_VYKONEJPOTREBU = new PříkazVykonejPotřebu(),
            PŘÍKAZ_ZAPLAT = new PříkazZaplať(),
            PŘÍKAZ_PUJCIT = new PříkazPůjčit(),
            PŘÍKAZ_NASTUP = new PříkazNastup(),
            PŘÍKAZ_OBJEDNAT = new PříkazObjednat(),
            PŘÍKAZ_ABRAKADABRA = new PříkazAbrakadabra(),
            
            PŘÍKAZ_KONEC = new PříkazKonec();

//== PROMĚNNÉ ATRIBUTY TŘÍDY ===================================================

     /** Příznak toho, je-li hra rozehraná nebo
     *  je-li skončená a bude se startovat nová. */
    private static boolean poprvé = true;

//== STATICKÝ INICIALIZAČNÍ BLOK - STATICKÝ KONSTRUKTOR ========================
//== KONSTANTNÍ ATRIBUTY INSTANCÍ ==============================================

     private final String název;
     private final String popis;

//== PROMĚNNÉ ATRIBUTY INSTANCÍ ================================================
//== PŘÍSTUPOVÉ METODY VLASTNOSTÍ TŘÍDY ========================================

     /***************************************************************************
     * Vrátí kolekci všech příkazů použitelných ve hře..
     *
     * @return Požadovaná kolekce
     */
    static Collection<ICommand> getPříkazy()
    {
        return název2příkaz.values();
    }

//== OSTATNÍ NESOUKROMÉ METODY TŘÍDY ===========================================

    /***************************************************************************
     * Zpracuje zadany prikaz a vrati text zpravy pro uzivatele.
     *
     * @param příkaz Zadavany prikaz
     * @return Textova odpoved hry na zadany prikaz
     */
    static String zpracujPříkaz(String příkaz)
    {
        příkaz = příkaz.toLowerCase();  //.trim();
        if (poprvé) {
            return start(příkaz);
        }
        if (příkaz.equals("")) {
            return PRÁZDNÝ;
        }
//        if (Stav.ROZHOVOR) {
//            return Rozhovor.reaguj(příkaz);                 //==========>
//        }
        String[] slova = příkaz.split("\\s+");
        ICommand  akce = název2příkaz.get(slova[0]);
        if (akce == null) {
            return NEZNÁM;                                  //==========>
        }
//        if (DBG.DEBUG < 0) {
//            povel.getParametry();
//        }

        String[] parametry = new String[slova.length-1];
        System.arraycopy(slova, 1, parametry, 0, parametry.length);

        String  odpověď = akce.execute(parametry);
        odpověď = doplň(odpověď);
        return  odpověď;
    }

     /***************************************************************************
     * Oznámení o ukončení hry.
     * Příští volání metody {@link #zpracujPříkaz(String)}
     * bude opět prvním voláním v nové hře.
     */
    public static void konec() {
        poprvé = true;
    }


//##############################################################################
//== KONSTRUKTORY A TOVÁRNÍ METODY =============================================

    /***************************************************************************
     * Vytvoří nový příkaz se zadaným názvem a popisem své funkce.
     *
     * @param název Název vytvářeného příkazu
     * @param popis Stručný popis funkce, použití a účelu příkazu
     */

    Příkaz (String název, String popis)
    {
        this.název = název;
        this.popis = popis;
        název2příkaz.put(název.toLowerCase(), this);
    }



//== ABSTRAKTNÍ METODY =========================================================

     /***************************************************************************
     * Metoda realizující reakci hry na zadaní daného příkazu.
     * Počet parametru je závislý na konkrétním příkazu, např. příkazy Konec
     * a Nápověda nemají parametry, příkazy Jdi a Vezmi mají jeden parametr
     * 
     *
     * @param parametry Parametry příkazu;
     *                  jejich počet muže byt pro každý příkaz jiný
     * @return Text zprávy vypsané po provedení příkazu
     */
    @Override
    public abstract String execute( String... parametry );


//== PŘÍSTUPOVÉ METODY VLASTNOSTÍ INSTANCÍ =====================================

       /***************************************************************************
     * Vraci nazev prikazu, tj. text, ktery musi hrac zadat
     * pro vyvolani daneho prikazu
     *
     * @return Nazev prikazu
     */
    @Override
    public String getName()
    {
        return název;
    }


    /***************************************************************************
     * Vraci popis prikazu s vysvetlenim jeho funkce
     * a vyznamu jednotlivych parametru.
     *
     * @return Popis prikazu
     */
    @Override
    public String getDescription()
    {
        return popis;
    }


    /***************************************************************************
     * Vrátí informaci o tom, jeli hra již skočena a lze-ji proto začít novou.
     * @return
     */
    static boolean isSkončeno()
    {
        return poprvé;
    }





//== OSTATNÍ NESOUKROMÉ METODY INSTANCÍ ========================================


       /***************************************************************************
     * Vrátí text s informacemi o aktuálním stavu hry.
     * 
     * @return Požadovaný informační text
     */
    private static String doplň(String  odpověď)
    {
        StringBuilder sb = new StringBuilder(odpověď);
        Collection<INamed> kolekce;

        Místnosti am = Místnosti.getAktuálníMístnost();
        // zde vypisuju popis místnosti
        sb.append("\nNacházíte se v místnosti: " + am.getName() + "\n" + am.getDescription() + "\n");
        připoj(sb, "Sousedé:  ", am.getNeighbors());
        připoj(sb, "Předměty: ", am.getObjects());
        připoj(sb, "Batoh:    ", Batoh.getBatoh().getObjects());

        return sb.toString();
    }


    /***************************************************************************
     * Do zadaného stringbuilderu přidá zadaný titulek
     * následovaný vyjmenovanými položkami ze zadané kolekce.
     *
     * @param sb       Doplňovaný StringBuilder
     * @param titulek  Přidávaný titulek
     * @param objekty  Kolekce přidávaných objektů
     */
    private static void připoj(StringBuilder sb, String titulek,
                        Collection<? extends INamed> objekty)
    {
        sb.append('\n').append(titulek).append(objekty);
    }


    /***************************************************************************
     * Odstartuje novou hru.
     */
    private static String start(String příkaz)
    {
        if (příkaz.equals("")) {
            Místnosti.inicializuj();
            Batoh   .inicializuj();
    //        Batoh.getBatoh().přidej(new Předmět ("peněženka"));
            poprvé = false;
            return UVÍTÁNÍ;                             //==========>
        } else {
            throw new IllegalStateException(
                                "Prvním příkazem není bezejmenný příkaz.");
        }
    }


    
//== SOUKROMÉ A POMOCNÉ METODY TŘÍDY ===========================================
//== SOUKROMÉ A POMOCNÉ METODY INSTANCÍ ========================================
//== INTERNÍ DATOVÉ TYPY =======================================================
//== TESTOVACÍ METODY A TŘÍDY ==================================================
//
//     /***************************************************************************
//      * Testovací metoda.
//      */
//     public static void test()
//     {
//         Příkaz instance = new Příkaz();
//     }
//     /** @param args Parametry příkazového řádku - nepoužívané. */
//     public static void main(String[] args)  {  test();  }
}
